package Server;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.NoSuchAlgorithmException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
//import RSA.*
import Conn.Conn;
import DES.DES;
import Message.Message;
import RSA.RSA;
import Ticket.Ticket;

public class Server {
    ServerSocket server = null;
    int port=1000;
    public String ID="00001";

    private Boolean isCorrect(Ticket t)
    {
        return true;
    }

    public Ticket toTicket(String s)
    {
        String []a=s.split("-");
        Ticket m=new Ticket(a[Ticket.pos.ID_src.ordinal()],
                a[Ticket.pos.ID_dst.ordinal()],
                Integer.parseInt(a[Ticket.pos.lifetime.ordinal()]),
                a[Ticket.pos.ADC.ordinal()],
                a[Ticket.pos.key.ordinal()]
        );
        String time=a[Ticket.pos.TS.ordinal()];
        int day=Integer.parseInt(time.substring(0,2));
        int hour=Integer.parseInt(time.substring(2,4));
        int minute=Integer.parseInt(time.substring(4,6));
        Calendar c=Calendar.getInstance();
        c.set(Calendar.HOUR,hour);
        c.set(Calendar.MINUTE,minute);
        c.set(Calendar.DATE,day);
        m.setTS(c);
        return m;
    }
    public Message toMessage(String s)
    {
        String []a=s.split("\\|");
        Message m=new Message(a[Message.pos.tag.ordinal()],
                a[Message.pos.ID_src.ordinal()],
                a[Message.pos.ID_dst.ordinal()],
                Integer.parseInt(a[Message.pos.lifetime.ordinal()]),
                a[Message.pos.content.ordinal()],
                a[Message.pos.redu.ordinal()]
                );
        String time=a[Message.pos.TS.ordinal()];
        int day=Integer.parseInt(time.substring(0,2));
        int hour=Integer.parseInt(time.substring(2,4));
        int minute=Integer.parseInt(time.substring(4,6));
        Calendar c=Calendar.getInstance();
        c.set(Calendar.HOUR,hour);
        c.set(Calendar.MINUTE,minute);
        c.set(Calendar.DATE,day);
        m.setTS(c);
        return m;
    }


    //服务器打开
    public void Start() {

        try {
            server = new ServerSocket(port);
            System.out.println("正在监听端口"+port);
        } catch (IOException e) {
            e.printStackTrace();
        }
        ExecutorService pool = Executors.newFixedThreadPool(5);


        //重写接口
        class myRunnable implements Runnable {
            DataOutputStream writer = null;
            DataInputStream reader = null;
            DES des=new DES();
//            RSA rsa=new RSA();
            Socket client=null;
            static int numb=0;



            public Message process(Message m)
            {
                Message newm=null;
                Ticket t=null;
                Conn c=new Conn();
                c.getConnection();
                String sql;
                ResultSet rs;
                String key_dt="";
                String key_td="";
                String key_dv="";
                String key_vd="";
                switch (Integer.parseInt(m.getTag()))
                {
                    case 1:
                        sql="select d_key_td,d_key_dt from device where d_ID='%s';".formatted(m.getID_src());
                        rs=c.execute(sql);
                        try {
                            rs.next();
                            key_dt=rs.getString(1);
                            key_td=rs.getString(2);
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                        if(Objects.equals(m.getID_dst(), new Server().ID))
                        {
                            t=new Ticket(new Server().ID,m.getID_src(),120,client.getInetAddress().getHostAddress(),key_td);
                            try {
                                newm=new Message("00004",new Server().ID,m.getID_src(),120,DES.encrypt(t.toStr(),DES.getSecretKey("00002")),key_dt);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                        break;
                    case 2:
                        try {
                            RSA.genarateKeyPair();
                            key_td=RSA.getPublicKey();
                            key_dt=RSA.getPrivateKey();
                            RSA.genarateKeyPair();
                            key_dv=RSA.getPrivateKey();
                            key_vd=RSA.getPublicKey();
                            sql="insert into device(d_ID,d_key_td,d_key_dt,d_key_dv,d_key_vd) values ('%s','%s','%s','%s','%s')"
                                    .formatted(m.getID_src(),key_td,key_dt,key_dv,key_vd);
                            c.execute(sql,0);
                            sql="select d_key_td,d_key_dt from device where d_ID='%s';".formatted(m.getID_src());
                            rs=c.execute(sql);
                            try {
                                rs.next();
                                key_dt=rs.getString(1);
                                key_td=rs.getString(2);
                            } catch (SQLException e) {
                                e.printStackTrace();
                            }
                            t=new Ticket(new Server().ID,m.getID_src(),120,client.getInetAddress().getHostAddress(),key_td);
                            try {
                                newm=new Message("00010",new Server().ID,m.getID_src(),120,DES.encrypt(t.toStr(),DES.getSecretKey("00002")),key_dt);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        } catch (NoSuchAlgorithmException e) {
                            e.printStackTrace();
                        }
                        break;
                    default:
                        newm=new Message("00000",new Server().ID,m.getID_src(),5,"error"," ");
                }
                return newm;
            }
            public void send(String s)
            {
                try {
                    writer.writeUTF(s);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            void send(String s,String key)
            {
//                Calendar cal=Calendar.getInstance();
//                key=key+ cal.getTime();
                try {
                    send(DES.encrypt(s,DES.getSecretKey(key)));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            String recv(String key)
            {
                String s=recv();
                try {
                    s=DES.decrypt(s,DES.getSecretKey(key));
                    return s;
                } catch (Exception e) {
                    return null;
                }
            }
            public String recv()
            {
                try {
                    return reader.readUTF();
                } catch (IOException e) {
                    return "";
                }
            }
            myRunnable(Socket nclient)
            {
                this.client = nclient;
                numb++;
                try {
                    DataOutputStream writer = new DataOutputStream(this.client.getOutputStream());
                    DataInputStream reader = new DataInputStream(this.client.getInputStream());
                    this.writer=writer;
                    this.reader=reader;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            @Override
            public void run()
            {
                Message m;
                Ticket t;
                System.out.println(Thread.currentThread().getName());
                System.out.println("serve for " + this.client.getInetAddress()+",linked with "+numb+" clinets");
                try
                {
                    while(true)
                    {
                        String s=recv();
                        if( s.equals(""))
                        {
                            break;
                        }
                        m=toMessage(s);
                        System.out.println("recv from client: "+m.toStr());
                        String k=" ";
                        m=process(m);
                        try {
                            System.out.println(m.toStr());
                            send (m.toStr(),m.getID_dst());
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }

                    client.close();
                    numb--;
                    System.out.println("client close\n");
                } catch (IOException e) {
                    e.printStackTrace();
                }

                //client.close();
            }
        } //重写Runnable接口


        //循环等待socket连接
        while(true){
            try {
                Socket new_client= server.accept();
                pool.execute(new myRunnable(new_client));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
